﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

using ComunesMGI.DataTypes;
using ComunesMGI.Enum;
using ComunesMGI.Constantes;

using MGI.AccesoDatos.AccesoSP;

using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;




namespace MGI.AccesoDatos
{
    class SharepointProxy: ISharepoint
    {

        #region ISharepoint Members

        /// <summary>
        /// Dado los títulos de los campos y otra información traida del xml 
        /// de configuración, se retorna una lista con información mas completa 
        /// (incluyendo la anterior) acerca de los campos, traida del sitio 
        /// sharepoint .
        /// </summary>
        /// <param name="cliente"></param>
        /// <param name="sistema"></param>
        /// <param name="tipoLista"></param>
        /// <param name="nomCampos"></param>
        /// <returns>List<DataCampo></returns>
        public List<DataCampo> GetCampos(string sitioSistema, Lista tipoLista, List<DataCampo> nomCampos) 
        
        {

            SPSite mySite = null;
            SPWeb myWeb = null;
            SPAcceso.Conectar(sitioSistema,ref mySite,ref myWeb);
            SPList spLista;
            switch (tipoLista)
            {
                case Lista.Incidentes:
                    spLista = myWeb.Lists[ConstantesMGI.NomListaIncidentes];
                    break;
                case Lista.Tareas:
                    spLista = myWeb.Lists[ConstantesMGI.NomListaTareas];
                    break;
                default:
                    spLista = myWeb.Lists[ConstantesMGI.NomListaIncidentes];
                    break;
            }
            List<DataCampo> campos = new List<DataCampo>();
            foreach (DataCampo dataCampo in nomCampos)
            {
                SPField spField = null;
                try
                {
                    spField = spLista.Fields[dataCampo.Titulo];
                }
                catch 
                {
                    throw new Exception("El nombre del campo " + dataCampo.Titulo + " del xml no existe en Sharepoint" );
                }
                CampoSharepoint tipoCampo = spTypeToCampoSharepoint(spField.TypeAsString);
                string tituloCampo = spField.Title;
                string internalCampo = spField.InternalName;
                int largoCampo = System.Convert.ToInt32(spField.DisplaySize);
                bool requeridoCampo = spField.Required;
                string defaultCampo = spField.DefaultValue;

                DataCampo dataCampo2 = new DataCampo(tipoCampo, tituloCampo, defaultCampo, requeridoCampo, null);
                dataCampo2.ParteMail = dataCampo.ParteMail;

                switch (tipoCampo)
                {
                    case CampoSharepoint.Choice:
                        List<string> cadaChoice = new List<string>();
                        foreach (string choice in ((SPFieldChoice)spField).Choices)
                        {
                            cadaChoice.Add(choice);
                        }
                        dataCampo2.Opciones = cadaChoice;
                        break;
                    default:
                        break;
                }
                campos.Add(dataCampo2);
            }
            SPAcceso.Desconectar(ref mySite, ref myWeb);
            return campos; 
        }





        /// <summary>
        /// Alta de incidente en sharepoint
        /// </summary>
        /// <param name="sistema"></param>
        public DataAltaIncidente AddIncidente(DataSistema sistema) 
        {
            SPSite mySite = null;
            SPWeb myWeb = null;
            SPList spLista = null;
            SPAcceso.ConectarLista(sistema.Sitio , ConstantesMGI.NomListaIncidentes, ref mySite, ref myWeb, ref spLista);
            DataAltaIncidente altaIncidente = SPAcceso.Impactar(myWeb, spLista, sistema.Campos);
            SPAcceso.Desconectar(ref mySite , ref myWeb);
            return altaIncidente;
        }


        public List<DataIncidente> GetIncidentes(string sitio) 
        {
            SPSite mySite = null;
            SPWeb myWeb = null;
            SPList spLista = null;
            SPAcceso.ConectarLista(sitio, ConstantesMGI.NomListaIncidentes, ref mySite, ref myWeb, ref spLista);
            List<DataIncidente> listaDataIncidente = new List<DataIncidente>();
            string tituloIncidente;
            int idIncidente;
            int idIssue;
            foreach (SPListItem spItem in spLista.Items)
            {
                idIncidente = int.Parse(spItem["ID"].ToString());
                idIssue = int.Parse(spItem["IssueID"].ToString());
                if (spItem["Título"] != null)
                {
                    tituloIncidente = spItem["Título"].ToString();
                }
                else
                {
                    tituloIncidente = "-no hay dato-";
                }

                //Si el id del incidente es igual al id antecesor 
                //(traducción inexacta) entonces
                //se trata del incidente inicial y no de una copia
                if (idIncidente == idIssue)
                {
                    DataIncidente dataIncidente = new DataIncidente(idIncidente, tituloIncidente);
                    listaDataIncidente.Add(dataIncidente);
                }
            }
            SPAcceso.Desconectar(ref mySite, ref myWeb); 
            return listaDataIncidente;
        }

        /// <summary>
        /// Retorna información de todos los incidentes en el sitio 
        /// del cliente-sistema
        /// </summary>
        /// <param name="cliente"></param>
        /// <param name="sistema"></param>
        /// <returns>List<DataIncidente></returns>
        public List<DataIncidenteReporte> GetIncidentesReporte(DataSistema sistema)
        {
            SPSite mySite = null;
            SPWeb myWeb = null;
            SPList spLista = null;
            SPAcceso.ConectarLista(sistema.Sitio, ConstantesMGI.NomListaIncidentes, ref mySite, ref myWeb, ref spLista);
            List<DataIncidenteReporte> listaDataIncidente = new List<DataIncidenteReporte>();
            string idIssue = null;
            string titulo = null;
            string url = null;
            string urlItem = null;
            string responsable = null;
            string nomSistema = null;
            string wp = null;
            string descripcion = null;
            string idIncidente = null;
            DateTime fechaPropuesto = ConstantesMGI.FechaVacia;
            DateTime fechaCierre = ConstantesMGI.FechaVacia;



            //obtiene la parte final de la url conteniendo el nombre de la lista
            int ini = spLista.DefaultViewUrl.LastIndexOf(ConstantesMGI.PageDefaultUrlLista + "/");
            //elimina la vista por defecto porque no permite acceso directo a la url del item
            //en su lugar usamos DispForm.aspx
            int largo = spLista.DefaultViewUrl.LastIndexOf("/") - ini;
            string parteLista = spLista.DefaultViewUrl.Substring(ini, largo) + "/" + ConstantesMGI.PageDefaultUrlListaItems;
            url = sistema.Sitio + "/" + parteLista; ;

            foreach (SPListItem spItem in spLista.Items)
            {
                idIssue = null;
                titulo = null;
               
                urlItem = null;
                responsable = null;
     
                wp = null;
                descripcion = null;
                idIncidente = null;

                if (spItem["ID"] != null && spItem["IssueID"] != null)
                {
                    idIncidente = spItem["ID"].ToString();
                    idIssue = spItem["IssueID"].ToString();
                    if (idIncidente == idIssue)
                    {
                        if (spItem["Título"] != null)
                        {
                            titulo = spItem["Título"].ToString();
                        }
                        urlItem = url + "?ID=" + idIncidente;

                        nomSistema = sistema.Nombre;

                        
                        if ((spItem["Asignado a"])!=null)
                        {
                            responsable = (spItem["Asignado a"]).ToString();
                            responsable = responsable.Substring(responsable.LastIndexOf("#")+1);
                        }
                        if (spItem["WP"] != null)
                        {
                            wp = spItem["WP"].ToString();
                        }
                        if (spItem["Descripción"] != null)
                        {
                            descripcion = spItem["Descripción"].ToString();
                        }
                        if (spItem["Fecha Propuesto"] != null)
                        {
                            fechaPropuesto = (DateTime)spItem["Fecha Propuesto"];
                        }
                        if (spItem["Fecha Cierre"] != null)
                        {
                            fechaCierre = (DateTime)spItem["Fecha Cierre"];
                        }

                        DataIncidenteReporte dataIncidente = new DataIncidenteReporte(idIncidente, titulo, urlItem, responsable, nomSistema, wp, descripcion, fechaPropuesto, fechaCierre);
                        listaDataIncidente.Add(dataIncidente);
                    }
                }
            }
            SPAcceso.Desconectar(ref mySite, ref myWeb);
            return listaDataIncidente;
        }


        public List<DataIncidente> GetIncidentesWP(string sitio, int idWorkPackage)
        {
            SPSite mySite = null;
            SPWeb myWeb = null;
            SPList spLista = null;
            SPAcceso.ConectarLista(sitio, ConstantesMGI.NomListaIncidentes,ref mySite,ref myWeb,ref spLista);
            List<DataIncidente> listaDataIncidente = new List<DataIncidente>();
            string tituloIncidente;
            int idIncidente;
            foreach (SPListItem spItem in spLista.Items)
            {
                if (spItem["WP"] != null)
                {
                    string textoWP = spItem["WP"].ToString();
                    if (idWorkPackage == System.Convert.ToInt32(textoWP))
                    {
                        idIncidente = int.Parse(spItem["ID"].ToString());
                        if (spItem["Título"] != null)
                        {
                            tituloIncidente = spItem["Título"].ToString();
                        }
                        else
                        {
                            tituloIncidente = "-no hay dato-";
                        }
                        DataIncidente dataIncidente = new DataIncidente(idIncidente, tituloIncidente);
                        listaDataIncidente.Add(dataIncidente);
                    }
                }
            }
            SPAcceso.Desconectar(ref mySite, ref myWeb); 
            return listaDataIncidente;
        }






        /// <summary>
        /// Retorna las tareas en el sitio  
        /// que esten asociadas al incidente indicado
        /// </summary>
        /// <param name="cliente"></param>
        /// <param name="sistema"></param>
        /// <param name="incidente"></param>
        /// <returns>List<DataTarea></returns>
        public List<DataTarea> GetTareas(string sitio, int idIncidente) 
        {
            SPSite mySite = null;
            SPWeb myWeb = null;
            SPList spLista = null;
            SPAcceso.ConectarLista(sitio, ConstantesMGI.NomListaTareas, ref mySite, ref myWeb, ref spLista);
            List<DataTarea> listaDataTarea = new List<DataTarea>();
            foreach (SPListItem spItem in spLista.Items)
            {
                if (spItem["IDOriginal"].ToString() == idIncidente.ToString())
                {
                    DataTarea dataTarea = new DataTarea(spItem["ID"].ToString(), spItem["Título"].ToString());
                    listaDataTarea.Add(dataTarea);
                }
            }
            SPAcceso.Desconectar(ref mySite, ref myWeb);
            return listaDataTarea;
        }

        
        /// <summary>
        /// Dado un incidente de determinado sistema, una tarea y un usuario,
        /// se asigna la tarea al usuario y se asocia la misma al incidente.
        /// 
        /// </summary>
        /// <param name="sistema"></param>
        /// <param name="incidente"></param>
        /// <param name="tarea"></param>
        /// <param name="usuario"></param>
        /// <returns>
        ///         Retorna la dirección de email del usuario al que se le quiere asignar la tarea
        ///         o si no es válido el mismo, se retorna null
        /// </returns>
        public string AsignarResponsable(string sitioSistema, int idIncidente, int idTarea, DataUsuario usuario)
        {
            SPSite mySite = null;
            SPWeb myWeb = null;
            SPList spLista = null;
            SPAcceso.ConectarLista(sitioSistema, ConstantesMGI.NomListaIncidentes, ref mySite, ref myWeb, ref spLista);

            SPListItem spItem = spLista.Items.GetItemById( idTarea);

            string mail = null;
            if (SPUtility.IsLoginValid(mySite, usuario.Nombre))
            {
                SPUser spUser = myWeb.AllUsers[usuario.Nombre];
                spItem["Asignado a"] = spUser;
                spItem["IDOriginal"] = idIncidente;
                spItem.Update();
                mail = spUser.Email;
            }

            SPAcceso.Desconectar(ref mySite, ref myWeb);
            return mail;

        }

        public void SetIncidenteWP(string sitio, int idWorkPackage, int idIncidente) 
        {
            SPSite mySite = null;
            SPWeb myWeb = null;
            SPList spLista = null;
            SPAcceso.ConectarLista(sitio, ConstantesMGI.NomListaIncidentes, ref mySite, ref myWeb, ref spLista);
            

            SPListItem spItem = spLista.Items.GetItemById(idIncidente);
            spItem["WP"] = idWorkPackage;
            spItem.Update();

            SPAcceso.Desconectar(ref mySite, ref myWeb);   
        }





        /// <summary>
        /// Escribe en un archivo temporal la información enviada por el stream.
        /// Es usado para Recibir archivos que posteriormente serán adjuntados a
        /// incidentes en el sharepoint.
        /// </summary>
        /// <param name="sourceStream"></param>
        /// <returns></returns>
        public string UploadFile(Stream sourceStream)
        {
            FileStream targetStream = null;

            int nroTemp=0; 
            string filePath="";
            string fileName="";
            string uploadFolder = @".\";
            DirectoryInfo dir = new DirectoryInfo(uploadFolder);



            //generar un nombre de archivo temporal que no exista
            Random idGen = new Random();
            bool existe =true;
            while (existe) 
            {                 
                nroTemp  = idGen.Next(0,999999999);

                fileName = "Upload" + nroTemp.ToString() + ".tmp";
                filePath = Path.Combine(uploadFolder, fileName);

                FileInfo archivo = new FileInfo(filePath);
                if (!archivo.Exists) 
                {
                    existe = false;
                }                  
            }
            
            try
            {
                using (targetStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
                {
                    const int bufferLen = 4096;
                    byte[] buffer = new byte[bufferLen];
                    int count = 0;
                    while ((count = sourceStream.Read(buffer, 0, bufferLen)) > 0)
                    {
                        targetStream.Write(buffer, 0, count);
                    }
                    targetStream.Close();
                    sourceStream.Close();
                }
                return nroTemp.ToString();
            }
            catch (Exception e)
            {
                throw new Exception("No se pudo crear el archivo temporal " + e.Message);
            }
        }





        /// <summary>
        /// Dada la existencia de un archivo temporal previamente cargado,  
        /// se envía a un sitio sharepoint y se adjunta a un incidente indicado 
        /// con el nombre indicado.
        /// </summary>
        /// <param name="nombreArchivo"></param>
        /// <param name="sistema"></param>
        /// <param name="incidente"></param>
        /// <param name="nroTemp"></param>
        /// <returns>indica si se pudo adjuntar</returns>
        public bool AdjuntarArchivoIncidente(string nombreArchivo, String urlSistema, int idIncidente, string nroTemp) 
        {
            try
            {
                string uploadFolder = @".\";
                string filename = "Upload" + nroTemp + ".tmp";
                string filePath = Path.Combine(uploadFolder, filename);
                FileInfo archivo = new FileInfo(filePath);

                if (archivo.Exists)
                {
                    byte[] contenido = File.ReadAllBytes(filePath);

                    SPSite mySite = null;
                    SPWeb myWeb = null;
                    SPList spLista = null;
                    SPAcceso.ConectarLista(urlSistema, ConstantesMGI.NomListaIncidentes, ref mySite, ref myWeb, ref spLista);

                    SPListItem spItem = spLista.Items.GetItemById(idIncidente);
                    spItem.Attachments.AddNow(nombreArchivo, contenido);
                    SPAcceso.Desconectar(ref mySite, ref myWeb);

                    File.Delete(filePath);
                    return true;
                }
                else
                {
                    //return false;
                    throw new Exception("No hay contenido cargado en el servidor");
                   
                }
            }
            catch (Exception e)
            {
                throw new Exception(e.Message);
            }
        }


        public DataAltaTarea AddTarea(string urlSistema,int idIncidente, List<DataCampo>campos)
        {
            SPSite mySite = null;
            SPWeb myWeb = null;
            SPList spLista = null;
            
            SPAcceso.ConectarLista(urlSistema, ConstantesMGI.NomListaTareas, ref mySite, ref myWeb, ref spLista);
            string [] datosRetorno = SPAcceso.Impactar2(myWeb, spLista, campos);
            SPAcceso.Desconectar(ref mySite, ref myWeb);
            
            return new DataAltaTarea(datosRetorno[0],datosRetorno[1]);
        }


        #endregion

  /*      /// <summary>
        /// Dada una lista de sharepoint y una lista de datacampo 
        /// conteniendo nombre de los campos, tipo y un valor para los 
        /// mismos, se realiza el alta en sharepoint con la información. 
        /// Se usa tambien el sitio sharepoint para obtener información sobre
        /// la conversión de fechas del formato "dd-mm-aaaa hh:mm" a
        /// cualquier formato configurado en el sharepoint.
        /// También se pueden adjuntar archivos.
        /// 
        /// Retorna ID y otra información de lo creado.
        /// </summary>
        /// <param name="myWeb"></param>
        /// <param name="spLista"></param>
        /// <param name="campos"></param>
        /// <param name="archivos"></param>
        /// <returns>DataAltaIncidente</returns>
        public DataAltaIncidente Impactar(SPWeb myWeb, SPList spLista, List<DataCampo> campos)
        {
            
            SPListItem newItem = spLista.Items.Add();
            foreach (DataCampo dataCampo in campos)
            {
                switch (dataCampo.Tipo)
                {
                    case CampoSharepoint.DateTime:
                        string[] fechaHora = dataCampo.Valor.Split(' ');
                        newItem[dataCampo.Titulo] = SPUtility.ParseDate(myWeb, fechaHora[0], fechaHora[1], false);
                        break;
                    default:
                        newItem[dataCampo.Titulo] = dataCampo.Valor;
                        break;
                }
            }
            newItem.Update();
            
            //obtiene la parte final de la url conteniendo el nombre de la lista
            int ini = spLista.DefaultViewUrl.LastIndexOf(ConstantesMGI.PageDefaultUrlLista + "/");
            //elimina la vista por defecto porque no permite acceso directo a la url del item
            //en su lugar usamos DispForm.aspx
            int largo = spLista.DefaultViewUrl.LastIndexOf("/") - ini;
            string parteLista = spLista.DefaultViewUrl.Substring(ini, largo) + "/" + ConstantesMGI.PageDefaultUrlListaItems;

            string url = spLista.ParentWeb.Url + "/" + parteLista + "?ID=" + newItem["ID"].ToString();
            return new DataAltaIncidente(newItem.ID.ToString(), url);
        }

        */

        /// <summary>
        /// Mapea los tipos de campos de sharepoint a los de MGI
        /// </summary>
        /// <param name="spType">String representando el tipo de datos de sharepoint</param>
        /// <returns></returns>
        public static CampoSharepoint spTypeToCampoSharepoint(string spType)
        {
            switch (spType)
            {
                case "Choice":
                    return CampoSharepoint.Choice;
                case "DateTime":
                    return CampoSharepoint.DateTime;
                case "Number":
                    return CampoSharepoint.Number;
                case "Text":
                    return CampoSharepoint.Text;
                case "Boolean":
                    return CampoSharepoint.Boolean;
                case "Note":
                    return CampoSharepoint.Note;
                case "User":
                    return CampoSharepoint.User;
                default:
                    throw new NotImplementedException();
            }
        }


    }
}
